/*******************************************************************
Leecher:
Overview:
To be called by manager, when updater returns with a seeder.
Arguments:
@filename:
@part_num:
@pointer to struct seeder:
********************************************************************/
#include "dstruct.h"
#include "header.h"
#include<sys/signal.h>
#include<sys/time.h>
#include<sys/resource.h>
#include<sys/wait.h>
#include<sys/errno.h>
#include<pthread.h>
#include<unistd.h>
#define BUFFSIZE 1024

#define DEBUG
int random_select(int max_pieces)
{
	static long a = 3003003;
	a = (a*250)%29763027;
	return (a%max_pieces);
	
}

void leecher_client(struct file_part *head,char *filename,int part_num)
{
	struct file_part *temp = head;
	char newpart[20];
	char buffer[BUFFSIZE],tempbuff[BUFFSIZE];
	char msg[50];
	char p_ack = 'P', n_ack = 'N';
	unsigned long int ip_addr;
	unsigned short int port;
	int sock;
	int no_of_pieces=0,random_piece=0,part_size,no_of_seeders=0;
	int size_counter=0,write_count=0,i;
	size_t bytes_read;
	struct leecher sin;
	pthread_mutex_t safe_leech=PTHREAD_MUTEX_INITIALIZER;
	//calculating number of pieces
#ifdef DEBUG
	printf("\n Filename received in head node :%s and filename %s, part num is%d", head->filename,filename, part_num);
	fflush(stdout);
#endif
	while(temp){
		no_of_pieces++;
		temp=temp->next;
	}
#ifdef DEBUG
	printf("\nNumber of pieces in file: %d",no_of_pieces);
	fflush(stdout);
#endif
	temp = head;
	while(temp->part_num != part_num){
		temp=temp->next;
	}
#ifdef DEBUG
	printf("\nI have to download part: %d",temp->part_num);
	fflush(stdout);
#endif
	//Now temp is at the reqd node.
	if(temp->part_num == no_of_pieces)
		part_size = temp->file_size - (no_of_pieces* PARTSIZE);
	else
		part_size = PARTSIZE;
	
	sprintf(newpart,"%s.part.%d",filename,part_num);
#ifdef DEBUG
	printf("\nNew part name is: %s",newpart);
	fflush(stdout);
#endif
	pthread_mutex_unlock(&safe_leech);
	pthread_mutex_lock(&safe_leech);
	temp->data_ptr = fopen(newpart,"ab+");
	if(!temp->data_ptr){
		printf("ERROR: file '%s' cannot be created.No space\n",newpart);
		exit(1);
	}
	pthread_mutex_unlock(&safe_leech);
	for(i=0;i<MAX_SEEDS;i++){
		if(temp->seeder_list[i].seeder_id)
			no_of_seeders++;
	}

#ifdef DEBUG
	printf("\nNo of seeders in the seeder list are: %d\n",no_of_seeders);
	fflush(stdout);
#endif

	random_piece = random_select(no_of_seeders);

#ifdef DEBUG
	printf("\nRandom piece to be selected is: %d\n",random_piece);
	fflush(stdout);
#endif


	memset(&sin.lc_sin,0,sizeof(sin.lc_sin));
	sin.lc_sin.sin_family = AF_INET;
	//get seeders address.
	pthread_mutex_lock(&safe_leech);
	
/*	
	ip_addr = ntohl(temp->seeder_list[random_piece].sd_sin.sin_addr.s_addr);
	if((sin.lc_sin.sin_addr.s_addr = htonl(ip_addr)) == INADDR_NONE){//update ip addr
		printf("Cant get IP address of seeder\n");
	}
	port = htons(temp->seeder_list[random_piece].sd_sin.sin_port);
	if((sin.lc_sin.sin_port = htons(port)) == 0){//update port number.
		printf("Can't get Port noumber of seeder\n");
	}
*/
/************************* Need to refine this logic ***********************/
	sin.lc_sin.sin_addr.s_addr=temp->seeder_list[0].sd_sin.sin_addr.s_addr;
	sin.lc_sin.sin_port=temp->seeder_list[0].sd_sin.sin_port;
	
	//memcpy(sin.lc_sin,temp->seeder_list[0].sd_sin,sizeof(temp->seeder_list[random_piece].sd_sin));
	
	inet_ntop(AF_INET, &(sin.lc_sin.sin_addr), tempbuff, BUFFSIZE);
#ifdef DEBUG
	printf("Random Number generated is: %d\n",random_piece);
#endif
	printf("\n Connecting to seeder on IP and Port :%s:%d\n",tempbuff,ntohs(sin.lc_sin.sin_port));
	fflush(stdout);
	
	
	//TODO : exit if no connection is formed
	
	pthread_mutex_unlock(&safe_leech);
	//create socket
	if((sock = socket(PF_INET,SOCK_STREAM,0))<0){
		printf("ERROR:Socket not created\n");
		exit(1);
	}
	//connect socket
	if(connect(sock,(struct sockaddr*)&sin.lc_sin,sizeof(sin.lc_sin))<0){
		printf("ERROR:Unable to connect to seeder\n");
		exit(1);
	}
	else{
		printf("Connected to seeder with ID:%d\n",temp->seeder_list[0].seeder_id);
	}
	
	printf("Downloading %s  of size %d ...",newpart,temp->file_size);
	sprintf(msg,"%s,%d%c",filename,part_num,'$');
	send(sock,msg,sizeof(msg),0);//sending the filename and part_num to the seeder
#ifdef DEBUG
	printf("\nSent filename and partnum to seeder\n");
	fflush(stdout);
#endif
	size_counter=0;
	
	while(size_counter != temp->file_size){
		bytes_read = recv(sock,buffer,BUFFSIZE,0);
#ifdef DEBUG
		printf("bytes read from socket:%d  ....",bytes_read);
		fflush(stdout);
#endif
		pthread_mutex_lock(&safe_leech);
		if(fwrite(buffer,sizeof(char),bytes_read,temp->data_ptr) == bytes_read){
		//fwrite(buffer,sizeof(char),bytes_read,temp->data_ptr);
			size_counter += bytes_read;
#ifdef DEBUG
			printf("Bytes written to file so far :%d\n",size_counter);
			fflush(stdout);
#endif
			write_count++;
			send(sock,&p_ack,sizeof(p_ack),0);
		}
		
		else {
			size_counter -= bytes_read;
			write_count--;
			printf("ERROR writing to file...\n");
			send(sock,&n_ack,sizeof(n_ack),0);
		}
		pthread_mutex_unlock(&safe_leech);
	/*	if(bytes_read==0)
		{
		break;
		fclose(temp->data_ptr);
		}*/
	}
	fclose(temp->data_ptr);
	close(sock);
	printf("\n Socket closed.. Closing file ptr ... \n");
	fflush(stdout);
	
	pthread_mutex_lock(&safe_leech);
	
	pthread_mutex_unlock(&safe_leech);
	
	pthread_mutex_lock(&safe_leech);
	temp->percent_downloaded = 100.00;
	temp->download_status = COMPLETE;
	pthread_mutex_unlock(&safe_leech);
	//CRC check
}
